package com.isomentricengine.core
{
	import com.isomentricengine.character.BaseCharacter;
	import com.isomentricengine.map.IMap;
	import com.isomentricengine.map.LevelMap;
	import com.isomentricengine.tile.BaseTile;
	import com.isomentricengine.tile.DoorTile;
	import com.isomentricengine.vo.Coordinates;
	import com.medusa.core.extension.MovieClipExtension;
	
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;

	public class GameEngine extends MovieClipExtension
	{
		private var keyRight:Boolean;
		private var keyLeft:Boolean;
		private var keyUp:Boolean;
		private var keyDown:Boolean;
		private var keySpace:Boolean;
		
		private var mainCharacter:BaseCharacter;
		private var maps:Array = [];
		private var currentMap:IMap;
		
		private var visibleRows:Number;
		private var visibleColumns:Number;
		private var centerX:Number;
		private var centerY:Number;	
		private var shiftAmountX:Number;
		private var shiftAmountY:Number;
		private var charCenterXFactor:Number;
		private var charCenterYFactor:Number;
		
		public function GameEngine(columns:Number, rows:Number)
		{
			super();
			visibleColumns = columns;
			visibleRows = rows;
			addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
		}
		
		public function addMap(map:IMap, mapID:int, build:Boolean = false):void
		{
			maps.push({map:map, id:mapID});
			
			map.mapIndex = mapID;
			map.build();

			if(build){
				currentMap = map as IMap;
				buildMap();
			}
		}	
		
		public function addCharacter(character:BaseCharacter, xTile:Number = 1, yTile:Number = 1, controllable:Boolean = false):void
		{
			placeCharacter(character, xTile, yTile);
			character.controllable = controllable;
			character.engine = this;
			character.map = currentMap;
			
			if(controllable){
				character.name = "mainCharacter";
				mainCharacter = character;				
				mainCharacter.fall();
			}
			
			addChild(character);			
		}
		
		private function changeMap(doorTile:BaseTile):void
		{
			var tile:DoorTile = DoorTile(doorTile);
			
			for(var a:int = 0; a<currentMap.tiles.length; a++){
				removeChild(currentMap.tiles[a]);
			}
			
			var currentMapID:Number = currentMap.mapIndex;
			var nextMapID:Number = (tile.doorType == "forward") ? currentMapID + 1 : currentMapID - 1;
			var newCharTileX:Number = 1;
			var newCharTileY:Number = tile.row;
			var newMap:LevelMap = maps[nextMapID].map as LevelMap;
			
			currentMap = newMap as IMap;			
			buildMap();
			
			removeChild(mainCharacter);
			placeCharacter(mainCharacter, newCharTileX, newCharTileY);
			mainCharacter.map = currentMap;
			addChild(mainCharacter);
			
			render = true;
		}
		
		private function buildMap():void
		{
			for(var a:int = 0; a<currentMap.tiles.length; a++){
				addChild(currentMap.tiles[a]);
			}
		}
		
		private function placeCharacter(character:BaseCharacter, xTile:Number = 1, yTile:Number = 1):void
		{
			character.x = (xTile * currentMap.tileW) + currentMap.tileW * 0.5;
			character.y = ((yTile + 1)  * currentMap.tileH) - (currentMap.tileH * 0.5);
			character.currentCoordinates = new Coordinates(xTile, yTile);			
		}
		
		private function detectKeys(e:Event):void
		{
			if(keySpace && !mainCharacter.isJumping){
				mainCharacter.isJumping = true;
				mainCharacter.jumpSpeed = mainCharacter.jumpStart;
			}
			
			if(keyRight){
				mainCharacter.cornerTiles = CoordinateUtil.getCorners(mainCharacter, currentMap, this, mainCharacter.x - mainCharacter.speed, mainCharacter.y);
				if(!mainCharacter.isClimbing || mainCharacter.cornerTiles.downleft && mainCharacter.cornerTiles.upleft && mainCharacter.cornerTiles.downright){
					mainCharacter.move(1, 0, 0);
				}				
			}else if(keyLeft){
				mainCharacter.cornerTiles = CoordinateUtil.getCorners(mainCharacter, currentMap, this, mainCharacter.x - mainCharacter.speed, mainCharacter.y);
				if(!mainCharacter.isClimbing || mainCharacter.cornerTiles.downleft && mainCharacter.cornerTiles.upleft && mainCharacter.cornerTiles.downright){
					mainCharacter.move(-1, 0, 0);	
				}
			}else if(keyUp){
				if(!mainCharacter.isJumping && mainCharacter.checkForUpLadder()){
					mainCharacter.climb(-1);
				}
			}else if(keyDown){
				if(!mainCharacter.isJumping && mainCharacter.checkForDownLadder()){
					mainCharacter.climb(1);
				}
			}
			
			if(mainCharacter.isJumping){
				mainCharacter.jump();
			}
			
			checkForDoor();
			mainCharacter.update();
			updateMapScroll();
		}
		
		private function updateMapScroll():void
		{
			var newX:Number = centerX - mainCharacter.x;
			var newY:Number = centerY - mainCharacter.y
			
			if(newX > 0){
				newX = 0;
			}else if(newX < (stage.stageWidth - width)){
				newX = stage.stageWidth - width;
			}
			
			if(newY > 0){
				newY = 0;
			}else if(newY < (stage.stageHeight - height)){
				newY = stage.stageHeight - height;
			}
			
			x = newX;
			y = newY;
		}
		
		private function checkForDoor():void
		{
			if(BaseTile(getChildByName("tile_" + mainCharacter.currentCoordinates.yTile + "_" + mainCharacter.currentCoordinates.xTile)).isDoor){				
				render = false;
				changeMap(BaseTile(getChildByName("tile_" + mainCharacter.currentCoordinates.yTile + "_" + mainCharacter.currentCoordinates.xTile)));
			}
		}
		
		/* main engine functions */		
		
        public function set render(value:Boolean):void
        {
        	if(value){
        		addEventListener(Event.ENTER_FRAME, detectKeys);
        	}else{
        		removeEventListener(Event.ENTER_FRAME, detectKeys);
        	}
        }
        
        /*
        handlers
        */
		
		private function keyDownHandler(event:KeyboardEvent):void
        {
            switch(event.keyCode)
            {
                case Keyboard.UP:
                    keyUp = true;
                    keyDown = false;
                    break;
    
                case Keyboard.DOWN:
                    keyDown = true;
                    keyUp = false;
                    break;
    
                case Keyboard.LEFT:
                    keyLeft = true;
                    keyRight = false;
                    break;
    
                case Keyboard.RIGHT:
                    keyRight = true;
                    keyLeft = false;
                    break;
                    
                case Keyboard.SPACE:
                    keySpace = true;
                    break;
            }
        }
        
        private function keyUpHandler(event:KeyboardEvent):void
        {
            switch(event.keyCode)
            {
                case Keyboard.UP:
                    keyUp = false;
                    break;
    
                case Keyboard.DOWN:
                    keyDown = false;
                    break;
    
                case Keyboard.LEFT:
                    keyLeft = false;
                    break;
    
                case Keyboard.RIGHT:
                    keyRight = false;
                    break;
                    
                case Keyboard.SPACE:
                    keySpace = false;
                    break;
            }
        }
        
        private function handleAddedToStage(e:Event):void
        {
        	stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            
            centerY = stage.stageHeight * 0.5;
            centerX = stage.stageWidth * 0.5;
        }
		
	}
}